/**
 * @copyright Copyright (c) 2025 
 * CSG Digital Grid Technology (Guangdong) Co., Ltd.
 * @author xxxcsg
 * @brief get_login_info工具，获取登录信息
 */

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <ifaddrs.h>
#include <netdb.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <linux/if.h>
#include <string.h>
#include "cJSON.h"
#include <time.h>
#include "common.h"
#include "eagle_eys_server.h"

// #define DEFAULT_JSON_PATH "/vendor/etc/dev_conf.json"

#ifndef NI_MAXHOST
#define NI_MAXHOST 1025
#endif

#define PORT 6543
#define SERVER_IP "127.0.0.1"
#define BUFFER_SIZE 1024

#define TIME_ARRAY 7
#define MANUALTIMELEN 20

typedef struct {
    char mon[16];
    char day[16];
    char time[16];
    char user[50];
    char srcIp[20];
    char srcPort[20];
    char dstIp[20];
    char dstPort[20];
    char cmd[10];
    char cmdOutput[10];
    char opTime[50];
} SSHLogInfo;

typedef enum
{
    SYSTEM_TIME_SEC,
    SYSTEM_TIME_MIN,
    SYSTEM_TIME_HOUR,
    SYSTEM_TIME_DAY,
    SYSTEM_TIME_MON,
    SYSTEM_TIME_YEAR,
    SYSTEM_TIME_MAX
}emSystemTimeArray;

// 解析日志行，填充 SSHLogInfo 结构
int parseLogLine(const char *logLine, SSHLogInfo *logInfo) 
{
    static time_t preTime = 0;
    struct tm tm_parsed;
    time_t parsed_time = 0;
    char tmp[64] = {0};
    sscanf(logLine, "%s  %s %s %*s %*s %*s %s %*s %*s %s %*s %s %*s %s %*s",
               logInfo->mon,  logInfo->day,  logInfo->time, logInfo->cmdOutput, logInfo->user, logInfo->dstIp, logInfo->dstPort);

    sprintf(tmp,"%s  %s %s",logInfo->mon,  logInfo->day,  logInfo->time);
    // 解析时间字符串
    if (!strptime(tmp, "%b %d %H:%M:%S", &tm_parsed)) {
        // fprintf(stderr, "Failed to parse the time string.\n");
        return 1;
    }

#ifndef SMALL
    tm_parsed.tm_year = 124;
#endif
    sprintf(logInfo->mon,"%d",tm_parsed.tm_mon+1);
    // 将解析后的tm结构转换为time_t
    parsed_time = mktime(&tm_parsed);

    // printf("parsed_time:%ld,preTime:%ld\n",parsed_time,preTime);

    if(parsed_time > preTime)
    {
        preTime = parsed_time;
    }
    else
    {
        return 1;
    }


    return 0;
}

int timeArray2utcSec(int *timeArray, time_t *utcSec)
{
    struct tm nowTm = {0};

    nowTm.tm_year = timeArray[SYSTEM_TIME_YEAR] - 1900;
    nowTm.tm_mon  = timeArray[SYSTEM_TIME_MON] - 1;
    nowTm.tm_mday = timeArray[SYSTEM_TIME_DAY];
    nowTm.tm_hour = timeArray[SYSTEM_TIME_HOUR];
    nowTm.tm_min  = timeArray[SYSTEM_TIME_MIN];
    nowTm.tm_sec  = timeArray[SYSTEM_TIME_SEC];
    *utcSec = mktime(&nowTm);

    return 0;
}


int strTimeToUTCSecond(const char *const pTime, time_t *nSecond)
{
    int sznTime[TIME_ARRAY] = {0};

    sscanf(pTime, "%04d-%02d-%02d %02d:%02d:%02d",
        &sznTime[SYSTEM_TIME_YEAR], &sznTime[SYSTEM_TIME_MON], &sznTime[SYSTEM_TIME_DAY],
        &sznTime[SYSTEM_TIME_HOUR], &sznTime[SYSTEM_TIME_MIN], &sznTime[SYSTEM_TIME_SEC]);
    timeArray2utcSec(sznTime, nSecond);

    return 0;
}

int UTCSecondTostrTime(char *pTime, time_t *nSecond)
{
    // time_t rawtime;
    struct tm *info;
    char buffer[80] = {0};

    //time(&nSecond);
    info = localtime(nSecond);
    strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", info);
    strncpy(pTime, buffer, MANUALTIMELEN);

    return 0;
}

int getTimeZone()
{
    FILE *fp = popen("date +%z", "r");
    if (fp == NULL) {
        // 处理错误
        return -1;
    }
 
    char buffer[128];
    while (fgets(buffer, sizeof(buffer), fp) != NULL) {
        // 处理命令输出
    }

    // printf("buffer: %s", buffer);

    pclose(fp);
    int timezone = 0;
    timezone = atoi(&buffer[1]) / 100;
    if ('-' == buffer[0])
    {
        timezone = -timezone;
    }

    return timezone;
}

// 生成 JSON 字符串
void generateJSON(const SSHLogInfo *logInfo) 
{
    char nowTime[64] = {0};
    struct tm *tm_now;
    time_t now;
    cJSON *root = cJSON_CreateObject();
    if(!root)
    {
        return;
    }

    time(&now);
    // printf("now:%ld\n",now);
    tm_now = localtime(&now);
    sprintf(nowTime,"%d-%s-%s %s",tm_now->tm_year+1900,logInfo->mon,logInfo->day,logInfo->time);
    // printf("nowTime:%s\n",nowTime);
    // int timezone_offset = tm_now->tm_gmtoff / 3600; // 获取时区偏移值 (秒数转小时)
    int timezone_offset = getTimeZone();
    // if(timezone_offset)
    {
        time_t timeSeconds = 0;
        strTimeToUTCSecond(nowTime, &timeSeconds);
        if(timezone_offset > 0)
        {
            timeSeconds = timeSeconds + timezone_offset * 3600;
        }
        else
        {
            timeSeconds = timeSeconds - abs(timezone_offset) * 3600;
        }
        UTCSecondTostrTime(nowTime, &timeSeconds);
    }
    if(!cJSON_AddStringToObject(root, "loginTime", nowTime))
    {
        goto exit;
    }
    if(!cJSON_AddStringToObject(root, "user", logInfo->user))
    {
        goto exit;
    }
    if(!cJSON_AddStringToObject(root, "srcIp", logInfo->srcIp))
    {
        goto exit;
    }
    if(!cJSON_AddNumberToObject(root, "srcPort", atoi(logInfo->srcPort)))
    {
        goto exit;
    }
    if(!cJSON_AddStringToObject(root, "dstIp", logInfo->dstIp))
    {
        goto exit;
    }
    if(!cJSON_AddNumberToObject(root, "dstPort", atoi(logInfo->dstPort)))
    {
        goto exit;
    }
    if(!cJSON_AddStringToObject(root, "cmd", "sshd"))
    {
        goto exit;
    }
    if(!cJSON_AddStringToObject(root, "cmdOutput", logInfo->cmdOutput))
    {
        goto exit;
    }
    if(!cJSON_AddStringToObject(root, "opTime", nowTime))
    {
        goto exit;
    }
    
    char *jsonString = cJSON_Print(root);
    printf("%s\n",jsonString);
    free(jsonString);
exit:
    cJSON_Delete(root);
    return;
}

// 查找与客户端IP地址对应的网口和IP地址
void find_interface_by_client_ip(const char *client_ip,char *srcIP) 
{
    struct ifaddrs *ifaddr, *ifa;
    int family;
    char host[NI_MAXHOST];
    char netmask_str[INET_ADDRSTRLEN];
    struct sockaddr_in *sa, *mask;
    uint32_t client_ip_addr, interface_ip_addr, interface_netmask;
    
    if (getifaddrs(&ifaddr) == -1) {
        // perror("getifaddrs");
        return;
    }

    // 将客户端IP地址转换为网络字节序
    if (inet_pton(AF_INET, client_ip, &client_ip_addr) != 1) {
        // perror("inet_pton failed for client IP");
        freeifaddrs(ifaddr);
        return;
    }


    for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) 
    {
        if (ifa->ifa_addr == NULL || ifa->ifa_netmask == NULL)
            continue;

        family = ifa->ifa_addr->sa_family;

        if (family == AF_INET) {
            sa = (struct sockaddr_in *)ifa->ifa_addr;
            mask = (struct sockaddr_in *)ifa->ifa_netmask;

            // 将接口IP地址和子网掩码转换为网络字节序
            interface_ip_addr = sa->sin_addr.s_addr;
            interface_netmask = mask->sin_addr.s_addr;

            // 检查客户端IP地址是否在接口的子网范围内
            if ((client_ip_addr & interface_netmask) == (interface_ip_addr & interface_netmask)) {
                inet_ntop(AF_INET, &sa->sin_addr, host, NI_MAXHOST);
                inet_ntop(AF_INET, &mask->sin_addr, netmask_str, INET_ADDRSTRLEN);
                // printf("Interface: %s, IP Address: %s, Netmask: %s\n", ifa->ifa_name, host, netmask_str);
                strncpy(srcIP,host,INET_ADDRSTRLEN);
            }
        }
    }


    freeifaddrs(ifaddr);
}

void printNullJson(void)
{
    cJSON *root = cJSON_CreateObject();
    if(!root)
    {
        return;
    }
    if(!cJSON_AddStringToObject(root, "loginTime", "NULL"))
    {
        goto exit;
    }
    if(!cJSON_AddStringToObject(root, "user", "NULL"))
    {
        goto exit;
    }
    if(!cJSON_AddStringToObject(root, "srcIp", "NULL"))
    {
        goto exit;
    }
    if(!cJSON_AddNumberToObject(root, "srcPort", 0))
    {
        goto exit;
    }
    if(!cJSON_AddStringToObject(root, "dstIp", "NULL"))
    {
        goto exit;
    }
    if(!cJSON_AddNumberToObject(root, "dstPort", 0))
    {
        goto exit;
    }
    if(!cJSON_AddStringToObject(root, "cmd", "NULL"))
    {
        goto exit;
    }
    if(!cJSON_AddStringToObject(root, "cmdOutput", "NULL"))
    {
        goto exit;
    }
    if(!cJSON_AddStringToObject(root, "opTime", "NULL"))
    {
        goto exit;
    }
    
    char *jsonString = cJSON_Print(root);
    printf("%s\n",jsonString);
    free(jsonString);
exit:
    cJSON_Delete(root);
    return;
}

void printfMesgJson(LoginMesg *mesg)
{
    cJSON *root = NULL;

    root = cJSON_CreateObject();
    if(!root)
    {
        return;
    }
    if(!cJSON_AddStringToObject(root, "loginTime", mesg->loginTime))
    {
        goto exit;
    }
    if(!cJSON_AddStringToObject(root, "user", mesg->user))
    {
        goto exit;
    }
    if(!cJSON_AddStringToObject(root, "srcIp", mesg->srcIP))
    {
        goto exit;
    }
    if(!cJSON_AddNumberToObject(root, "srcPort", atoi(mesg->srcPort)))
    {
        goto exit;
    }
    if(!cJSON_AddStringToObject(root, "dstIp", mesg->dstIP))
    {
        goto exit;
    }
    if(!cJSON_AddNumberToObject(root, "dstPort", atoi(mesg->dstPort)))
    {
        goto exit;
    }
    if(!cJSON_AddStringToObject(root, "cmd", "sshd"))
    {
        goto exit;
    }
    if(!cJSON_AddStringToObject(root, "cmdOutput", mesg->cmdOutput))
    {
        goto exit;
    }
    if(!cJSON_AddStringToObject(root, "opTime", mesg->opTime))
    {
        goto exit;
    }
    
    char *jsonString = cJSON_Print(root);
    printf("%s\n",jsonString);
    free(jsonString);
exit:
    cJSON_Delete(root);
    return;
}

int get_ext_login_info(void)
{
    int sock = 0, valread = 0;
    struct sockaddr_in serv_addr;
    char buffer[BUFFER_SIZE] = {0};
    EagleEysBusiness package = {0};

    // 创建socket
    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        // perror("socket creation failed");
        return -1;
    }

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(PORT);

    // 将IPv4地址换
    if(inet_pton(AF_INET, SERVER_IP, &serv_addr.sin_addr)<=0) {
        // perror("Invalid address/ Address not supported");
        return -1;
    }

    // 连接到服务器
    if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
        // perror("Connection Failed");
        return -1;
    }

    package.type = GET_LOGIN_INFO;
    // 发送消息给服务器
    send(sock, (char*)&package, sizeof(package), 0);
    // printf("Client: Message sent to server\n");

    // 接收服务器响应
    valread = read(sock, buffer, BUFFER_SIZE);
    // printf("read len:%d\n", valread);

    if(valread)
    {
        EagleEysBusinessPackage *tmp = (EagleEysBusinessPackage*)buffer;
        // printf("type:%d,len:%d\n", tmp->type, tmp->len);
        if(tmp->type == GET_LOGIN_INFO && tmp->len)
        {
            // TODO
            LoginMesg* mesg = (LoginMesg*)tmp->data;
            printfMesgJson(mesg);

            return 0;
        }
        else
        {
            return -1;
        }
    }
    else
    {
        // printf("recv error\n");
        return -1;
        
    }

    close(sock);

    return -1;
}

int main(int argc, char *argv[])
{
    if(argc == 2)
    {
        if(!strcmp(argv[1],"-v"))
        {
            printf_func_version(HAWK_EYE_FUNC_LOGIN_INFO);
            return 0;
        }
    }
    
    if(get_ext_login_info() == 0)
    {
        return 0;
    }
    
    FILE *fp;
	char cmd[128] = {0};
	char line[1024] = {0};
    int len = 0;
    SSHLogInfo logInfo = {0};
    // char ip[24] = {0};
    // if(get_ip_address(ip))
    // {
    //     printNullJson();
    //     exit(EXIT_FAILURE);
    // }

#ifdef SMALL
    sprintf(cmd,"grep -ai 'sshd' /var/log/messages | grep -i 'password' | tail -n 1");
#else
    sprintf(cmd,"grep -ai 'sshd' /data/log/sys/messages | grep -i 'password' | tail -n 1");
#endif
    // printf("cmd:%s\n",cmd);
    fp = popen(cmd, "r");
	if (fp == NULL)
	{
        printNullJson();
        return -1;
    }

	if (fgets(line, sizeof(line), fp) == NULL) 
	{
		pclose(fp);
		printNullJson();
        return -1;
	}

	pclose(fp);

    len = strlen(line);
    if(len == 0)
    {
        printNullJson();
        return -1;
    }

    // printf("line:%s\n",line);
    if(parseLogLine(line,&logInfo))
    {
        printNullJson();
        return 0;
    }

    find_interface_by_client_ip(logInfo.dstIp,logInfo.srcIp);
    // memcpy(logInfo.srcIp,ip,strlen(ip));
    strcpy(logInfo.srcPort,"22");
    // printf("mon:%s day:%s time:%s cmd:%s user:%s ip:%s port:%s,srcIp:%s,srcPort:%s\n",
    //         logInfo.mon,  logInfo.day,  logInfo.time, logInfo.cmdOutput, logInfo.user, logInfo.dstIp, logInfo.dstPort,logInfo.srcIp,logInfo.srcPort);
    generateJSON(&logInfo);
    return 0;
}
